package com.turtle3d.user.visualizators;

import java.util.ArrayList;

import javax.media.j3d.Appearance;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Material;
import javax.media.j3d.Shape3D;
import javax.vecmath.Color3f;
import javax.vecmath.Matrix4f;

import com.turtle3d.ResourceManager;
import com.turtle3d.formallanguage.VisualSymbol;
import com.turtle3d.formallanguage.symbol.Symbol;
import com.turtle3d.util.Randomizer;
import com.turtle3d.visualizator.VisualData;
import com.turtle3d.visualizator.Visualizator;

/**
 * Vizualizator that builds tree from trunk and leaf 3d objects. 
 * @author Marek Paterczyk <marek.paterczyk@gmail.com>
 *
 */
public class Tree2 extends Visualizator {
	
	public BranchGroup visualize(VisualData visualData){
		BranchGroup branchGroup = new BranchGroup();
		
		ArrayList<VisualSymbol> visualSequence = visualData.getVisualSequence();
				
		for(int i=0;i<visualSequence.size();i++){
			
			VisualSymbol visualSymbol = visualSequence.get(i);						
																				
			Float d = visualSymbol.getSymbol().getParameter(Symbol.DISTANCE);			
			
			/* F means tree trunk*/
			if(visualSymbol.getSymbol().equals(new Symbol("F"))){
				
				/* There are different trunk objects, depending
				 * on trunk radius.*/
				Shape3D trunk;
				float radius = visualSymbol.getSymbol().getParameter(Symbol.RADIUS);
				if(radius>=1.2f)
					trunk = ResourceManager.getShape3D("trunkBase");
				else if(radius<0.5)
					trunk = ResourceManager.getShape3D("trunkSimple");
				else
					trunk = ResourceManager.getShape3D("trunk");
				
				trunk.setName("Trunk");
				
				/* Scale is applied to the trunk object. It's non
				 * uniform, Y (height) and XZ (radius) are set
				 * independently.
				 */
				Matrix4f scale = new Matrix4f();
				scale.setIdentity();
				scale.setScale(d);
				scale.m00=visualSymbol.getSymbol().getParameter(Symbol.RADIUS);
				scale.m22=visualSymbol.getSymbol().getParameter(Symbol.RADIUS);
				Matrix4f transform = visualSymbol.getTransform();
				transform.mul(scale);

				branchGroup.addChild(createTransformGroup(transform, trunk));
			}
			/* L means leaf */
			if(visualSymbol.getSymbol().equals(new Symbol("L"))){
				
				boolean draw = true;
						
				/* If L has more then leafAppearanceAge iterations,
				 * leaf is not drawn.
				 */
				int age = visualSymbol.getSymbol().getAge();
				if(age>visualSymbol.getSymbol().getParameter("leafAppearanceAge"))
					draw = false;					
				
				/* Draw a leaf. face_leaf is just a squere. */
				if(draw){					
					Shape3D leaf = ResourceManager.getShape3D("face_leaf");
						
					/* Leaf color is randomized (one of three) */
					Appearance appearance = new Appearance();
					Material m = new Material();					
					m.setDiffuseColor(randomizeLeafColor());
					appearance.setMaterial(m);
					leaf.setAppearance(appearance);	
					
					leaf.setName("Leafs");
					
					Matrix4f scale = new Matrix4f();
					scale.setIdentity();																
					scale.setScale(visualSymbol.getSymbol().getParameter("leafSize"));
					Matrix4f transform = visualSymbol.getTransform();
					transform.mul(scale);								
	
					branchGroup.addChild(createTransformGroup(transform, leaf));
				}
			}
			
		}					
		
		return branchGroup;
	}
	
	public void setRequiredParameters(){
		setRequiredParamter("leafSize", 0.2f);
		setRequiredParamter("leafAppearanceAge", 3f);
	}
	
	private Color3f randomizeLeafColor(){
		Color3f leafColor;
		int rand = Randomizer.getRandomizer().getRandom().nextInt(3);
		if(rand==0)
			leafColor = new Color3f(1f,0,0);
		else if(rand==1)
			leafColor = new Color3f(0,1f,0);
		else
			leafColor = new Color3f(0,0,1f);
		
		return leafColor;
	}

}
